//-*-C++-*-
/***************************************************************************
 *
 *   Copyright (C) 2002 - 2020 by Willem van Straten
 *   Licensed under the Academic Free License version 2.1
 *
 ***************************************************************************/

// dspsr/Signal/General/dsp/Dedispersion.h

#ifndef __Dedispersion_h
#define __Dedispersion_h

#include "dsp/PlasmaResponse.h"

class ThreadContext;

namespace dsp {

  //! Phase-coherent dispersion removal frequency response function
  /* This class implements the phase-coherent dedispersion kernel, as
     determined by the frequency response of the interstellar
     medium. */

  class Dedispersion : public PlasmaResponse 
  {

  public:

    //! Conversion factor between dispersion measure, DM, and dispersion, D
    static const double dm_dispersion;

    //! Default constructor
    Dedispersion();

    //! Default constructor
    ~Dedispersion();

    //! Set up and calculate the impulse_pos and impulse_neg attributes
    void prepare (const Observation* input, unsigned channels);

    //! Set the dispersion measure attribute in the output Observation
    virtual void mark (Observation* output);

    //! Set the dispersion measure in \f${\rm pc\,cm}^{-3}\f$
    void set_dispersion_measure (double dm);

    //! Get the dispersion measure in \f${\rm pc\,cm}^{-3}\f$
    double get_dispersion_measure () const { return dispersion_measure; }

    //! Return the dispersive delay for the given frequency
    double delay_time (double freq) const override;

    //! Class computes the integer and fractional sample inter-channel dispersive delay
    class SampleDelay;

    //! Correct fractional inter-channel delay given the integer sample inter-channel delay
    void set_sample_delay (SampleDelay*);

    //! Get the integer sample inter-channel delay
    SampleDelay* get_sample_delay ();

    //! Build the frequency response kernel
    virtual void build (const Observation* input = 0);

    //! Compute the phases for a dedispersion kernel
    void build (std::vector<float>& phases, unsigned npts, unsigned nchan);

    //! Build delays in microseconds instead of phases
    void set_build_delays (bool delay = true);

  protected:

    //! The dispersion measure (DM)
    double dispersion_measure = 0.0;

    //! Used to compute inter-channel fractional sample delay
    Reference::To<SampleDelay> sample_delay;

    //! Build method returns delay in microseconds instead of phase
    bool build_delays = false;

    void build (unsigned ndat, unsigned nchan);

    friend class PlasmaResponse;

    //! Set up for the specified channel
    void build_setup (double chan_freq);
    double interchannel_fractional_sample_delay = 0.0;

    //! Return the phase of the kernel response 
    double build_compute (double chan_freq, double freq);
  };

}

#endif
